/*
 ============================================================================
 Name        : BresenhamCircle.c
 Author      : Jorge García
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>

#define SCREEN_HEIGHT 480
#define SCREEN_WIDTH 640

typedef struct {
	float x, y;
}Punto;

Punto centro;
Punto radio;

int numPuntos;
int screen[SCREEN_WIDTH][SCREEN_HEIGHT];

void inicializar (void);
void redimensiona (int alto, int ancho);
void dibuja (void);
void teclado (unsigned char key, int cx, int cy);
void raton (int boton, int estado, int cx, int cy);
void bresenhamAlgorithm(int cx, int cy, int r);
void limpiaScreen();
int my_round(float);
void dibujaPixel(int x, int y);
void dibujaPixeles(int x, int y, int dx, int dy);
int calculaRadioEntero(Punto a, Punto b);

int main(int argc, char* argv[]) {

   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (SCREEN_WIDTH, SCREEN_HEIGHT);
   glutInitWindowPosition (100, 105);
   glutCreateWindow ("Algoritmo de Bresenham para circulos");
   inicializar();

   glutDisplayFunc(dibuja);
   glutReshapeFunc(redimensiona);
   glutKeyboardFunc(teclado);
   glutMouseFunc(raton);
   glutMainLoop();

   return 0;
}

void inicializar () {
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   numPuntos = 0;

}

void redimensiona (int ancho, int alto) {

   glViewport(0, 0, ancho, alto);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   gluOrtho2D(0.0, (double)ancho, 0.0, (double)alto);
}

void teclado (unsigned char key, int cx, int cy) {

	switch (key) {
		case 27:
		   exit(0);
		break;

		default: break;
	}

	glutPostRedisplay();
}

void raton (int boton, int estado, int cx, int cy) {


	if (boton == GLUT_LEFT_BUTTON && estado == GLUT_DOWN) {

		if (numPuntos == 2) {
			numPuntos = 0;
		}

		if (numPuntos == 0) { //este punto sera un nuevo centro
			centro.x = cx;
			centro.y = SCREEN_HEIGHT - cy;

		} else if (numPuntos == 1) { //este punto sera un nuevo radio
			radio.x = cx;
			radio.y = SCREEN_HEIGHT - cy;
		}

		numPuntos++;

	}

	glutPostRedisplay();
}


void dibuja (void) {
	int i, j;

	glClear(GL_COLOR_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	limpiaScreen();
	if (numPuntos == 2) {
		bresenhamAlgorithm(centro.x, centro.y, calculaRadioEntero(centro, radio));
	}

	glPointSize(1.0);
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_POINTS);
		for(i = 0; i < SCREEN_WIDTH; i++) {
			for(j = 0; j < SCREEN_HEIGHT; j++) {
				if (screen[i][j]) {
					glVertex2i(i, j);
				}
			}
		}
	glEnd();

	//Pintar el centro y el radio
	glPointSize(4.0);
	glColor3f(1.0, 1.0, 0.0);
	glBegin(GL_POINTS);
		if (numPuntos > 0) {
			glVertex2i(centro.x, centro.y);
		}
		if (numPuntos > 1) {
			glVertex2i(radio.x, radio.y);
		}
	glEnd();

	glFlush();
}


void bresenhamAlgorithm (int cx, int cy, int r) {

	int x = 0, y = r, d = 3 - 2 * r;

	while (x <= y) {
		dibujaPixeles(x, y, cx, cy);
		if (d < 0) {
			d += 4*x + 6;
		} else {
			d += 4*(x - y) + 10;
			y--;
		}
		x++;
	}
}

void limpiaScreen() {
	int i, j;

	for (i = 0; i < SCREEN_WIDTH; i++) {
		for (j = 0; j < SCREEN_HEIGHT; j++) {
			screen[i][j] = 0;
		}
	}
}

int my_round (float n) {
	return floor(n + 0.5);
}


void dibujaPixel(int x, int y) {
	if (x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT) {
		screen[x][y] = 1;
	}
}

void dibujaPixeles(int x, int y, int dx, int dy) {
	dibujaPixel( x + dx,  y + dy);
	dibujaPixel( y + dx,  x + dy);
	dibujaPixel( x + dx, -y + dy);
	dibujaPixel(-y + dx,  x + dy);
	dibujaPixel(-x + dx,  y + dy);
	dibujaPixel( y + dx, -x + dy);
	dibujaPixel(-x + dx, -y + dy);
	dibujaPixel(-y + dx, -x + dy);
}

int calculaRadioEntero(Punto a, Punto b) {
	float d;

	d = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));

	return my_round(d);
}
